package com.cxh.supermarket.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cxh.supermarket.common.constant.CacheNames;
import com.cxh.supermarket.common.constant.UserConstants;
import com.cxh.supermarket.common.core.domain.PageQuery;
import com.cxh.supermarket.common.core.domain.entity.SysDept;
import com.cxh.supermarket.common.core.domain.entity.SysRole;
import com.cxh.supermarket.common.core.domain.entity.SysUser;
import com.cxh.supermarket.common.core.page.TableDataInfo;
import com.cxh.supermarket.common.core.service.UserService;
import com.cxh.supermarket.common.exception.ServiceException;
import com.cxh.supermarket.common.helper.DataBaseHelper;
import com.cxh.supermarket.common.helper.LoginHelper;
import com.cxh.supermarket.common.utils.InvitationCodeGenerator;
import com.cxh.supermarket.common.utils.ServletUtils;
import com.cxh.supermarket.common.utils.StreamUtils;
import com.cxh.supermarket.common.utils.StringUtils;
import com.cxh.supermarket.im.IMUtil;
import com.cxh.supermarket.im.Notification;
import com.cxh.supermarket.im.NotificationEnum;
import com.cxh.supermarket.im.NotificationUtil;
import com.cxh.supermarket.system.domain.SysPost;
import com.cxh.supermarket.system.domain.SysUserPost;
import com.cxh.supermarket.system.domain.SysUserRole;
import com.cxh.supermarket.system.domain.vo.SysMemberUserVo;
import com.cxh.supermarket.system.mapper.SysDeptMapper;
import com.cxh.supermarket.system.mapper.SysPostMapper;
import com.cxh.supermarket.system.mapper.SysRoleMapper;
import com.cxh.supermarket.system.mapper.SysUserMapper;
import com.cxh.supermarket.system.mapper.SysUserPostMapper;
import com.cxh.supermarket.system.mapper.SysUserRoleMapper;
import com.cxh.supermarket.system.service.ISysUserService;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 用户 业务层处理
 *
 * @author Lion Li
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysUserServiceImpl implements ISysUserService, UserService {

  private final SysUserMapper baseMapper;
  private final SysDeptMapper deptMapper;
  private final SysRoleMapper roleMapper;
  private final SysPostMapper postMapper;
  private final SysUserRoleMapper userRoleMapper;
  private final SysUserPostMapper userPostMapper;

  @Override
  public TableDataInfo<SysUser> selectPageUserList(SysUser user, PageQuery pageQuery) {
    Page<SysUser> page = baseMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user));
    return TableDataInfo.build(page);
  }

  /**
   * 根据条件分页查询用户列表
   *
   * @param user 用户信息
   * @return 用户信息集合信息
   */
  @Override
  public List<SysUser> selectUserList(SysUser user) {
    return baseMapper.selectUserList(this.buildQueryWrapper(user));
  }

  private Wrapper<SysUser> buildQueryWrapper(SysUser user) {
    Map<String, Object> params = user.getParams();
    QueryWrapper<SysUser> wrapper = Wrappers.query();
    wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
        .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId())
        .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
        .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
        .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
        .between(params.get("beginTime") != null && params.get("endTime") != null,
            "u.create_time", params.get("beginTime"), params.get("endTime"))
        .and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
          List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
              .select(SysDept::getDeptId)
              .apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors")));
          List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
          ids.add(user.getDeptId());
          w.in("u.dept_id", ids);
        });
    return wrapper;
  }

  /**
   * 根据条件分页查询已分配用户角色列表
   *
   * @param user 用户信息
   * @return 用户信息集合信息
   */
  @Override
  public TableDataInfo<SysUser> selectAllocatedList(SysUser user, PageQuery pageQuery) {
    QueryWrapper<SysUser> wrapper = Wrappers.query();
    wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
        .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId())
        .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
        .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
        .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber());
    Page<SysUser> page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper);
    return TableDataInfo.build(page);
  }

  /**
   * 根据条件分页查询未分配用户角色列表
   *
   * @param user 用户信息
   * @return 用户信息集合信息
   */
  @Override
  public TableDataInfo<SysUser> selectUnallocatedList(SysUser user, PageQuery pageQuery) {
    List<Long> userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId());
    QueryWrapper<SysUser> wrapper = Wrappers.query();
    wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
        .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id"))
        .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds)
        .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
        .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber());
    Page<SysUser> page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper);
    return TableDataInfo.build(page);
  }

  /**
   * 通过用户名查询用户
   *
   * @param userName 用户名
   * @return 用户对象信息
   */
  @Override
  public SysUser selectUserByUserName(String userName) {
    return baseMapper.selectUserByUserName(userName);
  }

  /**
   * 通过手机号查询用户
   *
   * @param phonenumber 手机号
   * @return 用户对象信息
   */
  @Override
  public SysUser selectUserByPhonenumber(String phonenumber) {
    return baseMapper.selectUserByPhonenumber(phonenumber);
  }

  /**
   * 通过用户ID查询用户
   *
   * @param userId 用户ID
   * @return 用户对象信息
   */
  @Override
  public SysUser selectUserById(Long userId) {
    return baseMapper.selectUserById(userId);
  }

  /**
   * 查询用户所属角色组
   *
   * @param userName 用户名
   * @return 结果
   */
  @Override
  public String selectUserRoleGroup(String userName) {
    List<SysRole> list = roleMapper.selectRolesByUserName(userName);
    if (CollUtil.isEmpty(list)) {
      return StringUtils.EMPTY;
    }
    return StreamUtils.join(list, SysRole::getRoleName);
  }

  /**
   * 查询用户所属岗位组
   *
   * @param userName 用户名
   * @return 结果
   */
  @Override
  public String selectUserPostGroup(String userName) {
    List<SysPost> list = postMapper.selectPostsByUserName(userName);
    if (CollUtil.isEmpty(list)) {
      return StringUtils.EMPTY;
    }
    return StreamUtils.join(list, SysPost::getPostName);
  }

  /**
   * 校验用户名称是否唯一
   *
   * @param user 用户信息
   * @return 结果
   */
  @Override
  public boolean checkUserNameUnique(SysUser user) {
    boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
        .eq(SysUser::getUserName, user.getUserName())
        .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
    return !exist;
  }

  /**
   * 校验手机号码是否唯一
   *
   * @param user 用户信息
   */
  @Override
  public boolean checkPhoneUnique(SysUser user) {
    boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
        .eq(SysUser::getPhonenumber, user.getPhonenumber())
        .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
    return !exist;
  }

  /**
   * 校验email是否唯一
   *
   * @param user 用户信息
   */
  @Override
  public boolean checkEmailUnique(SysUser user) {
    boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
        .eq(SysUser::getEmail, user.getEmail())
        .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
    return !exist;
  }

  /**
   * 校验用户是否允许操作
   *
   * @param user 用户信息
   */
  @Override
  public void checkUserAllowed(SysUser user) {
    if (ObjectUtil.isNotNull(user.getUserId()) && user.isAdmin()) {
      throw new ServiceException("不允许操作超级管理员用户");
    }
  }

  /**
   * 校验用户是否有数据权限
   *
   * @param userId 用户id
   */
  @Override
  public void checkUserDataScope(Long userId) {
    if (!LoginHelper.isAdmin()) {
      SysUser user = new SysUser();
      user.setUserId(userId);
      List<SysUser> users = this.selectUserList(user);
      if (CollUtil.isEmpty(users)) {
        throw new ServiceException("没有权限访问用户数据！");
      }
    }
  }

  /**
   * 新增保存用户信息
   *
   * @param user 用户信息
   * @return 结果
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int insertUser(SysUser user) {
    // 新增用户信息
    int rows = baseMapper.insert(user);
    // 新增用户岗位关联
    insertUserPost(user);
    // 新增用户与角色管理
    insertUserRole(user);
    return rows;
  }

  /**
   * 注册用户信息
   *
   * @param user 用户信息
   * @return 结果
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean registerUser(SysUser user) {
    user.setCreateBy(user.getUserName());
    user.setUpdateBy(user.getUserName());
    user.setRegisterIp(ServletUtils.getClientIP());
    // 注册设备解析 填充
    if (ObjectUtil.isEmpty(user.getRegisterDevice())) {
      user.setRegisterDevice(ServletUtils.getRequest().getHeader("device-brand"));
    }

    boolean reg = baseMapper.insert(user) > 0;
    //生成我的邀请码
    String invitationCode = InvitationCodeGenerator.generateInvitationCode(user.getUserId() + "");
    baseMapper.update(
        Wrappers.<SysUser>lambdaUpdate().set(SysUser::getMyInvitationCode, invitationCode).eq(SysUser::getUserId, user.getUserId()));

    //注册环信账号
    IMUtil.createUser(user.getUserId(), user.getUserId() + "", UserConstants.WORKER);
    IMUtil.createUser(user.getUserId(), user.getUserId() + "", UserConstants.EMPLOYER);

    //发送系统消息
    Notification notification =
        NotificationUtil.getNotification(NotificationEnum.REGISTER_SUCCESS.getBusinessName(), null, null, false);
    //环信发送系统消息
    //IMUtil.sendSystemCustomMessageToUser(Collections.singletonList(user.getUserId()), notification);

    return reg;
  }

  /**
   * 修改保存用户信息
   *
   * @param user 用户信息
   * @return 结果
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int updateUser(SysUser user) {
    Long userId = user.getUserId();
    // 删除用户与角色关联
    userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
    // 新增用户与角色管理
    insertUserRole(user);
    // 删除用户与岗位关联
    userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, userId));
    // 新增用户与岗位管理
    insertUserPost(user);
    return baseMapper.updateById(user);
  }

  /**
   * 用户授权角色
   *
   * @param userId  用户ID
   * @param roleIds 角色组
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void insertUserAuth(Long userId, Long[] roleIds) {
    userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
        .eq(SysUserRole::getUserId, userId));
    insertUserRole(userId, roleIds);
  }

  /**
   * 修改用户状态
   *
   * @param user 用户信息
   * @return 结果
   */
  @Override
  public int updateUserStatus(SysUser user) {
    return baseMapper.updateById(user);
  }

  /**
   * 修改用户基本信息
   *
   * @param user 用户信息
   * @return 结果
   */
  @Override
  public int updateUserProfile(SysUser user) {
    return baseMapper.updateById(user);
  }

  /**
   * 修改用户头像
   *
   * @param userName 用户名
   * @param avatar   头像地址
   * @return 结果
   */
  @Override
  public boolean updateUserAvatar(String userName, String avatar) {
    return baseMapper.update(null,
        new LambdaUpdateWrapper<SysUser>()
            .set(SysUser::getAvatar, avatar)
            .eq(SysUser::getUserName, userName)) > 0;
  }

  /**
   * 重置用户密码
   *
   * @param user 用户信息
   * @return 结果
   */
  @Override
  public int resetPwd(SysUser user) {
    return baseMapper.updateById(user);
  }

  /**
   * 重置用户密码
   *
   * @param userName 用户名
   * @param password 密码
   * @return 结果
   */
  @Override
  public int resetUserPwd(String userName, String password) {
    return baseMapper.update(null,
        new LambdaUpdateWrapper<SysUser>()
            .set(SysUser::getPassword, password)
            .eq(SysUser::getUserName, userName));
  }

  /**
   * 新增用户角色信息
   *
   * @param user 用户对象
   */
  public void insertUserRole(SysUser user) {
    this.insertUserRole(user.getUserId(), user.getRoleIds());
  }

  /**
   * 新增用户岗位信息
   *
   * @param user 用户对象
   */
  public void insertUserPost(SysUser user) {
    Long[] posts = user.getPostIds();
    if (ArrayUtil.isNotEmpty(posts)) {
      // 新增用户与岗位管理
      List<SysUserPost> list = StreamUtils.toList(Arrays.asList(posts), postId -> {
        SysUserPost up = new SysUserPost();
        up.setUserId(user.getUserId());
        up.setPostId(postId);
        return up;
      });
      userPostMapper.insertBatch(list);
    }
  }

  /**
   * 新增用户角色信息
   *
   * @param userId  用户ID
   * @param roleIds 角色组
   */
  public void insertUserRole(Long userId, Long[] roleIds) {
    if (ArrayUtil.isNotEmpty(roleIds)) {
      // 新增用户与角色管理
      List<SysUserRole> list = StreamUtils.toList(Arrays.asList(roleIds), roleId -> {
        SysUserRole ur = new SysUserRole();
        ur.setUserId(userId);
        ur.setRoleId(roleId);
        return ur;
      });
      userRoleMapper.insertBatch(list);
    }
  }

  /**
   * 通过用户ID删除用户
   *
   * @param userId 用户ID
   * @return 结果
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int deleteUserById(Long userId) {
    // 删除用户与角色关联
    userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
    // 删除用户与岗位表
    userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, userId));
    return baseMapper.deleteById(userId);
  }

  /**
   * 批量删除用户信息
   *
   * @param userIds 需要删除的用户ID
   * @return 结果
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int deleteUserByIds(Long[] userIds) {
    for (Long userId : userIds) {
      checkUserAllowed(new SysUser(userId));
      checkUserDataScope(userId);
    }
    List<Long> ids = Arrays.asList(userIds);
    // 删除用户与角色关联
    userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, ids));
    // 删除用户与岗位表
    userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, ids));
    return baseMapper.deleteBatchIds(ids);
  }

  /**
   * 绑定用户微信信息
   *
   * @param userId    用户id
   * @param openid    openid
   * @param unionid   unionid
   * @param secretKey 秘钥
   */
  @Override
  public Boolean bindWxInfo(Long userId, String openid, String unionid, String secretKey) {
    LambdaUpdateWrapper<SysUser> sysUserLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
    sysUserLambdaUpdateWrapper.set(SysUser::getOpenid, openid).set(SysUser::getUnionid, unionid).set(SysUser::getSecretKey, secretKey)
        .isNull(SysUser::getUnionid).eq(SysUser::getUserId, userId);

    return baseMapper.update(sysUserLambdaUpdateWrapper) > 0;
  }

  /**
   * 会员用户列表
   *
   * @param status
   * @param keyword
   * @param pageQuery
   * @return
   */
  @Override
  public TableDataInfo<SysMemberUserVo> selectPageMemberUserList(String status, String keyword, PageQuery pageQuery, String cityName,
                                                                 String authStatus, String ip,
                                                                 String beginTime, String endTime) {

    //Page<SysMemberUserVo> MemberUserVo = new Page<>();
    //分页查询
    //Page<SysUser> page = baseMapper.selectVoPage(pageQuery.build(), queryWrapper);
    IPage<SysMemberUserVo>
        memberUserVo = baseMapper.selectUserPage(pageQuery.build(), status, keyword, cityName, authStatus, ip, beginTime, endTime);

    return TableDataInfo.build(memberUserVo);
  }

  @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId")
  @Override
  public String selectUserNameById(Long userId) {
    SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
        .select(SysUser::getUserName).eq(SysUser::getUserId, userId));
    return ObjectUtil.isNull(sysUser) ? null : sysUser.getUserName();
  }

}
